﻿using System;

namespace ch02.binary
{
    public static class LEB128
    {
        // https://en.wikipedia.org/wiki/LEB128#Decode_unsigned_integer
        public static (ulong, int) DecodeVarUint(byte[] data, int size)
        {
            var result = (ulong) 0;
            for (var i = 0; i < data.Length; i++)
            {
                var b = data[i];
                if (i == size / 7)
                {
                    if ((b & 0x80) != 0)
                    {
                        throw Errors.ErrIntTooLong;
                    }

                    if (b >> (size - i * 7) > 0)
                    {
                        throw Errors.ErrIntTooLarge;
                    }
                }

                result |= ((ulong) b & 0x7f) << (i * 7);
                if ((b & 0x80) == 0)
                {
                    return (result, i + 1);
                }
            }

            throw Errors.ErrUnexpectedEnd;
        }

        // https://en.wikipedia.org/wiki/LEB128#Decode_signed_integer
        public static (long, int) DecodeVarInt(byte[] data, int size)
        {
            var result = 0L;
            for (var i = 0; i < data.Length; i++)
            {
                var b = data[i];
                if (i == size / 7)
                {
                    if ((b & 0x80) != 0)
                    {
                        Panic.Run("errIntTooLong");
                    }

                    if ((b & 0x40) == 0 && b >> (size - i * 7 - 1) != 0 ||
                        (b & 0x40) != 0 && (short) (b | 0x80) >> (size - i * 7 - 1) != -1)
                    {
                        Panic.Run("errIntTooLarge");
                    }
                }

                result |= ((long) (b) & 0x7f) << (i * 7);
                if ((b & 0x80) != 0) continue;
                if (i * 7 < size && (b & 0x40) != 0)
                {
                    result |= -1 << ((i + 1) * 7);
                }

                return (result, i + 1);
            }

            throw Errors.ErrUnexpectedEnd;
        }
    }
}